﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NetFrameworkExtensions.Utils
{
  [Serializable]
  public class DeferredReference<T> : ReferenceBase<T>, IDisposable
  {
    IReference<T> innerReference;
    bool canChange;

    public DeferredReference(IReference<T> innerReference) : this(innerReference, true) { }

    public DeferredReference(IReference<T> innerReference, bool canChange)
    {
      if (innerReference == null) throw new ArgumentNullException("innerReference");
      this.innerReference = innerReference;
      this.canChange = canChange;
      this.innerReference.ValueChanged += innerReference_ValueChanged;
    }

    void innerReference_ValueChanged(object sender, ValueChangedEventArgs<T> e)
    {
      if (e.PreviousValue.HasValue)
        OnValueChanged(e.Value, e.PreviousValue.Value);
      else
        OnValueChanged(e.Value);
    }

    public override T Value
    {
      get
      {
        return innerReference.Value;
      }
      set
      {
        CheckCanChange();
        innerReference.Value = value;
      }
    }

    public override bool CanChange
    {
      get { return canChange && innerReference.CanChange; }
    }

    #region IDisposable Members

    public void Dispose()
    {
      if (innerReference == null) return;
      innerReference.ValueChanged -= innerReference_ValueChanged;
      innerReference = null;
    }

    ~DeferredReference()
    {
      Dispose();
    }

    #endregion
  }
}
